const GLOBE_RADIUS = 100;

/**
 * 计算三维空间中的三次方贝塞尔曲线上的点
 * @param t 进度
 * @param p0 起点
 * @param p1 控制点1
 * @param p2 控制点2
 * @param p3 终点
 * @returns
 */
export const cubicBezier3D = (
  t: number,
  p0: number[],
  p1: number[],
  p2: number[],
  p3: number[]
) => {
  let x =
    Math.pow(1 - t, 3) * p0[0] +
    3 * Math.pow(1 - t, 2) * t * p1[0] +
    3 * (1 - t) * Math.pow(t, 2) * p2[0] +
    Math.pow(t, 3) * p3[0];

  let y =
    Math.pow(1 - t, 3) * p0[1] +
    3 * Math.pow(1 - t, 2) * t * p1[1] +
    3 * (1 - t) * Math.pow(t, 2) * p2[1] +
    Math.pow(t, 3) * p3[1];

  let z =
    Math.pow(1 - t, 3) * p0[2] +
    3 * Math.pow(1 - t, 2) * t * p1[2] +
    3 * (1 - t) * Math.pow(t, 2) * p2[2] +
    Math.pow(t, 3) * p3[2];

  return [x, y, z];
};

/**
 * 地球坐标2笛卡尔坐标
 * @param lat
 * @param lng
 * @param relAltitude
 * @returns
 */
export const polar2Cartesian = (lat: number, lng: number, relAltitude = 0) => {
  const phi = ((90 - lat) * Math.PI) / 180;
  const theta = ((90 - lng) * Math.PI) / 180;
  const r = GLOBE_RADIUS * (1 + relAltitude);
  return {
    x: r * Math.sin(phi) * Math.cos(theta),
    y: r * Math.cos(phi),
    z: r * Math.sin(phi) * Math.sin(theta),
  };
};

/**
 * 笛卡尔坐标2地球坐标
 */
export const cartesian2Polar = ({
  x,
  y,
  z,
}: {
  x: number;
  y: number;
  z: number;
}) => {
  const r = Math.sqrt(x * x + y * y + z * z);
  const phi = Math.acos(y / r);
  const theta = Math.atan2(z, x);

  return {
    lat: 90 - (phi * 180) / Math.PI,
    lng: 90 - (theta * 180) / Math.PI - (theta < -Math.PI / 2 ? 360 : 0), // keep within [-180, 180] boundaries
    altitude: r / GLOBE_RADIUS - 1,
  };
};

/**
 * 判断坐标是否在范围内
 * @param point
 * @param polygon
 * @returns
 */
export const isPointInPolygon = (point: [number, number], polygon: any) => {
  let [x, y] = point;
  let inside = false;

  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
    const [xi, yi] = polygon[i];
    const [xj, yj] = polygon[j];

    const intersect =
      yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
    if (intersect) inside = !inside;
  }

  return inside;
}
